<?php
/**
 * @Tag v1.0.2
 */
namespace AmazonAdvertisingApi\Api;

use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\MultipartStream;
use GuzzleHttp\Psr7\Request;
use AmazonAdvertisingApi\ApiException;
use AmazonAdvertisingApi\ObjectSerializer;

/**
 * AuthorizationV1Api Class Doc Comment
 *
 * @category Class
 * @package  SellingPartnerApi
 */
class AuthorizationApi extends BaseApi
{
    public const NA = 'https://www.amazon.com';

    // Europe
    public const EU = 'https://eu.account.amazon.com';

    // Far East
    public const FE = 'https://apac.account.amazon.com';

    /**
     * @param string $redirect_uri
     * @param string $endpoint
     *    NA|EU|FE
     * @param $returnAuthUrl
     * @return string|void
     */
    public function createAuthRequest(string $redirect_uri,string $endpoint ='NA', $returnAuthUrl = false)
    {
        $params = [
            'client_id' => $this->config->getLwaClientId(),
            'scope' =>'advertising::campaign_management',//advertising::audiences
            'response_type'=>'code',
            'redirect_uri'=>$redirect_uri
        ];

        $authUrl = constant("self::{$endpoint}") . '/ap/oa?' . http_build_query($params);
        if ($returnAuthUrl) {
            return $authUrl;
        }
        header('Location: '.$authUrl);
        exit;
    }

    public function getRefreshToken(string $code,string $redirect_uri)
    {
        $response = $this->getRefreshTokenWithHttpInfo($code,$redirect_uri);
        return $response;
    }


    public function getRefreshTokenWithHttpInfo(string $code,string $redirect_uri)
    {
        $request = $this->getRefreshTokenRequest($code, $redirect_uri);
        try {
            $options = $this->createHttpClientOption();
            try {
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? $e->getResponse()->getBody()->getContents() : null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    $response->getBody()
                );
            }

            $responseBody = $response->getBody();
            if ($returnType === '\SplFileObject') {
                $content = $responseBody; //stream goes to serializer
            } else {
                $content = $responseBody->getContents();
                if (!in_array($returnType, ['string','integer','bool'])) {
                    $content = json_decode($content);
                }
            }
            return [
                ObjectSerializer::deserialize($content->payload, $returnType, []),
                $response->getStatusCode(),
                $response->getHeaders()
            ];

        } catch (ApiException $e) {
            throw $e;

        }
    }

    public function getRefreshTokenAsync(string $code,string $redirect_uri)
    {
        return $this->getRefreshTokenAsyncWithHttpInfo( $code, $redirect_uri);
    }

    public function getRefreshTokenAsyncWithHttpInfo(string $code,string $redirect_uri)
    {
        $returnType = '\SellingPartnerApi\Model\AuthorizationV1\getRefreshTokenResponse';
        $request = $this->getRefreshTokenRequest($code, $redirect_uri);
        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    $responseBody = $response->getBody();
                    if ($returnType === '\SplFileObject') {
                        $content = $responseBody; //stream goes to serializer
                    } else {
                        $content = $responseBody->getContents();
                        if ($returnType !== 'string') {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders()
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();
                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        $response->getBody()
                    );
                }
            );
    }

    /**
     * @param string $code
     * @param string $redirect_uri
     * @return Request
     */
    public function  getRefreshTokenRequest(string $code,string $redirect_uri)
    {
        $resourcePath = '';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;
        $formParams['grant_type']='authorization_code';
        $formParams['client_id']=$this->config->getLwaClientId();
        $formParams['client_secret']=$this->config->getLwaClientSecret();
        // form params
        if ($code !== null) {
            $formParams['code'] = ObjectSerializer::toFormValue($code);
        }
        if ($redirect_uri !== null) {
            $formParams['redirect_uri'] = ObjectSerializer::toFormValue($redirect_uri);;
        }
        if ($multipart) {
            $headers = $this->headerSelector->selectHeadersForMultipart(
                ['application/json', 'payload', 'errors']
            );
        } else {
            $headers = $this->headerSelector->selectHeaders(
                ['application/json', 'payload', 'errors'],
                [],
                "authorization_code"
            );
        }
        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);

            } elseif ($headers['Content-Type'] === 'application/json') {
                $httpBody = \GuzzleHttp\json_encode($formParams);

            } else {
                // for HTTP post (form)
                $httpBody = \GuzzleHttp\Psr7\Query::build($formParams);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = \GuzzleHttp\Psr7\Query::build($queryParams);
        return new Request(
            'POST',
            'https://api.amazon.com/auth/o2/token' . $resourcePath . ($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

}
